#include "relationport.h"

RelationPort::RelationPort(QGraphicsItem *parent) : QGraphicsItemGroup(parent)
{
    this->setGraphicsEffect(0);

    this->_linePen.setWidth(1);

    this->_lineGraphicsItem.setZValue(std::numeric_limits<int>::min() + 1);
    this->_lineGraphicsItem.setPen(this->_linePen);
    this->addToGroup(&this->_lineGraphicsItem);

    this->_decoratorGraphicsItem.setZValue(-std::numeric_limits<int>::infinity());
    this->_decoratorGraphicsItem.setVisible(false);
    this->addToGroup(&this->_decoratorGraphicsItem);

    this->_cardinalityLabel.setVisible(false);
    this->_cardinalityLabel.setBrush(this->_palette.relationCardinalityBackground());
    this->_cardinalityLabel.setZValue(std::numeric_limits<int>::max());
    this->addToGroup(&this->_cardinalityLabel);

    this->_roleLabel.setVisible(false);
    this->_roleLabel.setBrush(this->_palette.relationRoleBackground());
    this->_roleLabel.setZValue(std::numeric_limits<int>::max());
    this->addToGroup(&this->_roleLabel);

    this->updateTextPos();
}

RelationPort::~RelationPort()
{
    this->removeFromGroup(&this->_decoratorGraphicsItem);
    this->removeFromGroup(&this->_cardinalityLabel);
    this->removeFromGroup(&this->_roleLabel);

    //this->scene()->removeItem(&this->_decoratorGraphicsItem);
    //this->scene()->removeItem(&this->_cardinalityLabel);
    //this->scene()->removeItem(&this->_roleLabel);

    //this->scene()->removeItem(this);
}

QPoint RelationPort::itemBorderPoint()
{
    return this->_line.p1();
}

void RelationPort::setItemBorderPoint(QPoint itemBorderPoint)
{
    this->_line.setP1(itemBorderPoint);
    this->_lineGraphicsItem.setLine(this->_line);

     this->_decoratorGraphicsItem.setPos(itemBorderPoint);

    this->updateTextPos();
}

QPoint RelationPort::joinPoint()
{
    return this->mapToScene(this->_line.p2()).toPoint();
}

void RelationPort::setJoinPoint(QPoint joinPoint)
{
    this->_line.setP2(joinPoint);
    this->_lineGraphicsItem.setLine(this->_line);
}

UmlRelation* RelationPort::relation()
{
    return this->_relation;
}

void RelationPort::setRelation(UmlRelation *relation)
{
    if (!relation) {
        return;
    }

    this->_lineGraphicsItem.setPen(relation->linePenForRelationType(relation->relationType()));

    if ((relation->relationIsOfType(UmlRelation::UmlGeneralizationRelationType | UmlRelation::UmlRealizationRelationType)) &&
        this == relation->port2()) {
        this->_decoratorGraphicsItem.setPolygon(GeneralizationDeocrator());
        this->_decoratorGraphicsItem.setVisible(true);
    }

    else if (relation->relationIsOfType(UmlRelation::UmlAggregationRelationType)  &&
        this == relation->port1()) {
        this->_decoratorGraphicsItem.setPolygon(AggregationDecorator());
        this->_decoratorGraphicsItem.setVisible(true);
    }

    else if (relation->relationIsOfType(UmlRelation::UmlCompositionRelationType) &&
        this == relation->port1()) {
        this->_decoratorGraphicsItem.setPolygon(AggregationDecorator());
        this->_decoratorGraphicsItem.setFillBlack(true);
        this->_decoratorGraphicsItem.setVisible(true);
    }

    else {
        this->_decoratorGraphicsItem.setVisible(false);
    }
}

void RelationPort::setPen(QPen pen)
{
    pen.setWidth(1);

    this->_decoratorGraphicsItem.setPen(pen);
    this->_lineGraphicsItem.setPen(pen);
}

void RelationPort::setCardinality(UmlCardinality cardinality)
{
    this->_cardinalityLabel.setVisible(!cardinality.isNull());

    this->_cardinalityLabel.setText(cardinality.toUmlString());

    this->updateTextPos();
}

void RelationPort::setRole(QString role)
{
    this->_roleLabel.setText(role);

    this->_roleLabel.setVisible(!role.isEmpty() || !role.isNull());

    this->updateTextPos();
}

void RelationPort::setDirection(UmlRelation::RelativeItemPosition direction)
{
    this->_direction = direction;

    switch(direction) {
    case UmlRelation::NORTH :
        this->_decoratorGraphicsItem.setRotation(-90);
        break;
    case UmlRelation::SOUTH :
        this->_decoratorGraphicsItem.setRotation(90);
        break;
    case UmlRelation::WEST :
        this->_decoratorGraphicsItem.setRotation(-180);
        break;
    default :
        break;
    }
}

void RelationPort::setLinePen(QPen pen)
{
    this->_lineGraphicsItem.setPen(pen);
}

QVariant RelationPort::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemSceneHasChanged) {

        this->_cardinalityLabel.setParentItem(this);
        this->addToGroup(&this->_cardinalityLabel);

        this->_roleLabel.setParentItem(this);
        this->addToGroup(&this->_roleLabel);

        this->_lineGraphicsItem.setParentItem(this);
        this->addToGroup(&this->_lineGraphicsItem);

        this->_decoratorGraphicsItem.setParentItem(this);
        this->addToGroup(&this->_decoratorGraphicsItem);

        this->updateTextPos();
    }

    return QGraphicsItemGroup::itemChange(change, value);
}

void RelationPort::updateTextPos()
{
    QPointF cPos;
    QPointF rPos;

    switch(this->_direction) {
    case UmlRelation::NORTH :
        cPos.setX(this->itemBorderPoint().x() - this->_cardinalityLabel.boundingRect().width() - 5);
        cPos.setY(this->itemBorderPoint().y() - this->_cardinalityLabel.boundingRect().height() - 5);
        rPos.setX(this->itemBorderPoint().x() + 10);
        rPos.setY(this->itemBorderPoint().y() - this->_roleLabel.boundingRect().height() - 5);
        break;

    case UmlRelation::SOUTH :
        cPos.setX(this->itemBorderPoint().x() + 10);
        cPos.setY(this->itemBorderPoint().y() + 5);
        rPos.setX(this->itemBorderPoint().x() - this->_roleLabel.boundingRect().width() - 5);
        rPos.setY(this->itemBorderPoint().y() + 5);
        break;

    case UmlRelation::WEST :
        cPos.setX(this->itemBorderPoint().x() - this->_cardinalityLabel.boundingRect().width() - 5);
        cPos.setY(this->itemBorderPoint().y() + 5);
        rPos.setX(this->itemBorderPoint().x() - this->_roleLabel.boundingRect().width() - 5);
        rPos.setY(this->itemBorderPoint().y() - this->_roleLabel.boundingRect().height() - 5);
        break;

    default :
        cPos.setX(this->itemBorderPoint().x() + 10);
        cPos.setY(this->itemBorderPoint().y() - this->_cardinalityLabel.boundingRect().height() - 5);
        rPos.setX(this->itemBorderPoint().x() + 10);
        rPos.setY(this->itemBorderPoint().y() + 5);
        break;
    }

    this->_cardinalityLabel.setPos(cPos);
    this->_roleLabel.setPos(rPos);
}
